#include <stdio.h>
#include <string.h>
#include <iostream>
#include <queue>
#include <stdlib.h>
#include <fstream>
#include "online-certifier/communicator/decoderCommunicator.hh"
#include "mandelbaum.h"

using namespace std;

void *__gxx_personality_v0;//this is define to fix a linker bug in some machines

int main(int argc , char** argv)
{
	
    size_t k, NbErrors,i;
           fixedBitSizeInteger modulus,residue;

    integer bigModulus,bigResidue,modulusMax,bigModulusNeg,bigResidueNeg,modulusMaxNeg;

    Lifter lifter;
    Lifter lifterNeg;


    int port;
    char* dataproxy_addr;
    int dataproxy_port;
/*************************** reading arguments **************/
    if(argc == 1){//read from config file
        ifstream conf("decoder.conf");
        if(!conf.is_open()){
            perror("Can't read frontend.conf");
            exit(1);
        }
        int i;
        string line;
        for(i=0; !conf.eof();){
            getline(conf, line);
            if(!(line.empty() || line[0] == '#' )){
                if(i == 0){
                    port = atoi(line.c_str());
                }else if(i == 1){
                    dataproxy_addr = new char[line.size()];
                    strcpy(dataproxy_addr, line.c_str());

                }else if(i==2)
                    dataproxy_port = atoi(line.c_str());

                i++;
            }
        }
        if(i < 3){
            cerr << "[decoder] wrong decoder.config!!" << endl;
            exit(1);
        }

    }
    else if(argc ==4){
        port = atoi(argv[1]);
        dataproxy_addr = argv[2];
        dataproxy_port = atoi(argv[3]);
    
    }
    else {
        cerr << "wrong arguments!" << endl;
        cerr << "Usage: decoder port dataproxy_addr dataproxy_port" << endl;
        exit(1);
    }

/************************* finish reading arguments **************************/

    decoderCommunicator comm (port, dataproxy_addr, dataproxy_port); // initilizing the communication object to communicate with frontend and data proxy
    if(comm.runDecoderServer() == ERROR) exit(1); // start listening to the front end
    if(comm.connectToDataProxy() == ERROR) exit(1); 
    
    e_status res,res2;
    while (1)
    {
    
        printf("waiting for decoding command from the front end\n");
        res = comm.readFromFrontend(&k, &NbErrors); // reads one value from the front end and buffer the other values
        if (res == TERMINATED){
            cout << "frontend: terminate.." << endl;
            comm.terminate();
            return 0;
        }else if (res == SUCCESS){

            i=0;

            comm.resetCounter(); // for printing use
            while(i<k)
            {
                res2 = comm.readFromDataProxy(&residue, &modulus);
                if(res2 == SUCCESS) 
                {   lifter.AddOneValue(modulus, residue);
                    lifterNeg.AddOneValue(modulus, modulus - residue);
                    i++;
                }else if(res2 == DISCONNECTED || res2 == TIMEOUT)
                    break;
            }
            cout << "[decoder] decoding ..." << endl;

            lifter.GetCurrentResult(bigResidue,bigModulus,modulusMax);
            lifterNeg.GetCurrentResult(bigResidueNeg,bigModulusNeg,modulusMaxNeg);

            Decoder decoder(bigResidue,bigModulus,modulusMax,NbErrors);
            Decoder decoderNeg(bigResidueNeg,bigModulusNeg,modulusMaxNeg,NbErrors);

            decoder.BoundDecode_And_SendResults(comm); 
            decoderNeg.BoundDecode_And_SendResults(comm);

        }
        else if(res == DISCONNECTED){ 
            break;       
        }
    }
    delete dataproxy_addr;

    return 0;
}


